using Joystick_Pack.Scripts.Joysticks;
using UnityEngine;

namespace Player
{
    public class PlayerMovement : MonoBehaviour
    {
        [Header("References")]
        [SerializeField] private Collider _groundCollider;
        // ReSharper disable once NotAccessedField.Local
        [SerializeField] private FloatingJoystick _joystick;
        [SerializeField] private AudioSource _flightSound;
        [Space]
        [SerializeField] private Animator _animator;
        [SerializeField] private Rigidbody _rb;
        [SerializeField] private Player _player;
        [SerializeField] private Collider _collider;
        [Header("Ground")]
        [SerializeField, Min(0.0001f)] private float _groundBoundsOffset;
        [Header("Movement")]
        [SerializeField] private float _speed;
        [SerializeField] private float _flyForce;
        [SerializeField] private float _velocityLimitY;
        [Header("Other")]
        [SerializeField] private float _stamina;

        public AudioSource FlightSound => _flightSound;
        public Animator Anim => _animator;
        
        private bool _isCollisionEntered;
        private bool _isSpacePressed;
        private bool _isButtonPressed;
        private bool _isFlying;
        private Transform _selfTransform;
        private Transform _camera;
        private Vector3 _direction;
        private Quaternion _cameraRotation;
        private Bounds _groundBounds;
        private static readonly int _isFlyingHash
            = Animator.StringToHash("isFlying");
        
        private void Start()
        {
            _selfTransform = transform;
            // ReSharper disable once PossibleNullReferenceException
            _camera = Camera.main.transform;
            
            _groundBounds = _groundCollider.bounds;
            _groundBounds.size += Vector3.up * _groundBoundsOffset;
            _groundBounds.center += Vector3.up * _groundBoundsOffset;
        }

        private void OnValidate()
        {
            _animator = GetComponent<Animator>();
            _rb = GetComponent<Rigidbody>();
            _player = GetComponent<Player>();
            _collider = GetComponent<Collider>();
        }

        private void Update()
        {
            _isSpacePressed = Input.GetKey(KeyCode.Space);
            _isFlying = _isSpacePressed || _isButtonPressed;
            _animator.SetBool(_isFlyingHash, _isFlying);

            if (Input.GetKeyDown(KeyCode.Space) && !_isButtonPressed)
                _flightSound.Play();
            
            if (Input.GetKeyUp(KeyCode.Space) && !_isButtonPressed)
                _flightSound.Stop();
            
#if UNITY_STANDALONE
            float horizontal = Input.GetAxisRaw("Horizontal");
            float vertical = Input.GetAxisRaw("Vertical");
#else
        float horizontal, vertical;
        if (_joystick.Direction == Vector2.zero)
        {
            horizontal = Input.GetAxisRaw("Horizontal");
            vertical = Input.GetAxisRaw("Vertical");
        }
        else
        {
            horizontal = _joystick.Direction.x;
            vertical = _joystick.Direction.y;
        }
#endif

            _direction = new Vector3(horizontal, 0, vertical);
            _cameraRotation = Quaternion.Euler(0, _camera.eulerAngles.y, 0);
            _selfTransform.rotation = _cameraRotation;
        }

        private void FixedUpdate()
        {
            if (_isFlying)
            {
                _rb.velocity += Vector3.up * _flyForce;
            }

            Vector3 velocity = _rb.velocity;

            if (velocity.y > _velocityLimitY)
            {
                _rb.velocity = new Vector3(
                    velocity.x,
                    _velocityLimitY,
                    velocity.z
                );
            }

            if (_collider.bounds.Intersects(_groundBounds)) return;

            _rb.velocity = Utils.Vec3XyzToVec3Xz(
                _cameraRotation * _direction * _speed, velocity.y);
        }

        private void OnCollisionEnter(Collision other)
        {
            foreach(ContactPoint point in other.contacts)
            {
                if (point.impulse.magnitude >= _stamina)
                {
                    _player.Kill("разбился");
                }
            }
        }

        public void OnButtonDown()
        {
            _isButtonPressed = true;
            if (!_isSpacePressed)
                _flightSound.Play();
        }

        public void OnButtonUp()
        {
            _isButtonPressed = false;
            if (!_isSpacePressed)
                _flightSound.Stop();
        }
    }
}
